package com.hb.B_面向对象.F_模式匹配


fun main() {

}

/**
 * Num类表示某个整数的值
 * Operate类则是一个树形结构，他被用来表示一些复杂的表达式，其中opName树形表示常见的操作符，比如加减乘除
 */
sealed class Expr {
    data class Num(val value: Int) : Expr()
    data class Operate(val opNum: String, val left: Expr, val right: Expr) : Expr()
}

/**
 * 在进行整数表达式计算的时候，你往往会遇到许多可以简化的表达式，
 * 比如"1+0"就可以简化为1，"1*0"就可以简化为0.我们现在实现一个比较
 * 简单的需求：将"0+x"或者"x+0"简化为x,其他情况返回表达式本身.
 *
 * expr is Expr.Operate:判断给定的表达式是否是Operate类型
 * expr.opNum == "+" ：判断给定的表达式是否是假发操作
 * expr.left is Expr.Num：判断给定的表达式的左节点是否是数值0
 * expr.left.value == 0 :如果左节点是数值并且还得满足数值是0
 */
fun simplifyExpr(expr: Expr): Expr =
    if (expr is Expr.Num) {
        expr
    } else if (expr is Expr.Operate && expr.opNum == "+"
        && expr.left is Expr.Num && expr.left.value == 0
    ) {
        expr.right
    } else if (expr is Expr.Operate && expr.opNum == "+"
        && expr.right is Expr.Num && expr.right.value == 0
    ) {
        expr.left
    } else {
        expr
    }

/**
 *
 * 总结：模式匹配中的模式就是表达式，模式匹配的要匹配的就是表达式。模式匹配的核心其实就是解构
 * 也就是反向构造表达式--给定一个复杂的数据结构，然后将之前用来构成复杂结构的参数抽取出来。
 * */

/**
 * 与前面实现的方法相比，的确简洁了许多，并且也能够很清楚的推断出将要匹配的表达式的解构是什么样的。
 * 但是上面的实现还是需要我们去写判断类型的语句，而且当嵌套的层数变多的时候，单纯使用when表达式还是显得无力
 */
fun simplifyExpr2(expr: Expr): Expr =
    when (expr) {
        is Expr.Num -> expr
        is Expr.Operate ->
            //when递归
            when (expr) {
                Expr.Operate("+", Expr.Num(0), expr.right) -> expr.right
                Expr.Operate("+", expr.left, Expr.Num(0)) -> expr.left
                else -> expr
            }
    }
